﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once

#include "GcmpGeometryInterface.h"
#include "OwnerPtr.h"
#include "Vector2i.h"
#include "IVertex.h"

#include "Vector3d.h"
#include "GmSlopeArrowData.h"
#include "Coordinate3d.h"
#include "MultiSectionLoftEnums.h"
#include "GcmpApiDeclaration.h"
#include "GeometryErrorCode.h"

namespace gcmp
{
    class ILine2d;
    class ILine3d;
    class ICurve2d;
    class ICurve3d;
    class IPlane;
    class ISurface;
    class IBody;
    class IFace;
    class IEdge;
    class IPolygon;
    class IPolyCurve;
    class IPolyCurve3d;
    class IGraphicsNodeIdAsker;
    class IMesh;
    class IExtrudeFaceToPathProfileIndexMap;
    class ISweepFaceToPathProfileIndexMap;
    class IMultiSectionLoftFaceToPathProfileIndexMap;
    class IBlendFaceToPathProfileIndexMap;


    /// \brief 扫描标架的定义方式
    ///
    /// 
    enum class SweepType : int32_t
    {
        Perpendicular = 0,          ///< 每一个位置截面始终垂直于轨迹线
        Upright = 1,         ///< 指定竖直向上的方向（局部标架的Y轴）
        Facepoint = 2          ///< 扫描面的法向始终保持不变
    };

    /// \brief 扫描选项，构造扫描体的选项控制，后期会扩展
    struct SweepOptions
    {
        SweepType SwpType = SweepType::Perpendicular; ///< 设置截面沿路径扫描过程中的方向：目前仅支持Perpendicular（始终垂直于轨迹线）
    };

    /// \brief 放样类型的定义方式
    ///
    /// 
    enum class LoftType : int32_t
    {
        Default = -1,  ///<默认值
        Perpendicular = 0,  ///< 每一个位置截面始终垂直于轨迹线
        Upright = 1  ///< 指定竖直向上的方向（局部标架的Y轴）
    };

    /// \brief 顶面和底面放样融合选项
    struct BlendOptions
    {
        double DistEpsilon = 1E-4; ///< 距离容差
        LoftType Type = LoftType::Default; ///< 放样类型（目前仅支持Default和Perpendicular类型）
        IBody* Spine = nullptr; ///< 脊线（WireBody）
        std::vector<std::pair<const IVertex*, const IVertex*>> LoftVerticesMap; ///< 两截面顶点匹配关系，如果顶点数相同，可仅指定起始顶点匹配关系
        bool StartVerticesMap = true;///<LoftVerticesMap是否为起始顶点匹配关系
    };

    /// \brief 多截面放样选项
    struct MultiSectionLoftOptions
    {
        double DistEpsilon = 1E-4; ///< 距离容差，一般使用这个默认值即可
        std::vector<const IBody*> GuideBodies; ///< 引导线（WireBody）
        MultiSectionLoftVertexMatchMode Mode = MultiSectionLoftVertexMatchMode::Default; ///< 顶点匹配模式（默认匹配模式(需指定匹配点)、比率模式、顶点模式），默认为 Default
        std::vector<std::vector<const IVertex*>> LoftVerticesMap; ///< 多截面顶点匹配关系（结合默认匹配模式使用），目前需要指定全部拓扑点的匹配
        std::vector<std::pair<const IEdge*, Vector3d>> ClosedPoints; ///< 闭合点：当截面为壳体时有效；当截面为线框体时，必须是闭合的才有效
        double MinSegmentLength = 1.0; ///< 极小段长度（截面线中的极小段，或比率模式下打断后的极小段），一般使用这个默认值即可
        bool Linear = false;  ///< 侧面是否为两两直线连接，默认为 false
        bool DevidedByGuideCurve = true;  ///< 引导线是否分割面（引导线是否为边线），默认为 true
    };

    /// \brief 构造壳体错误类型
    enum class ShellErrorStatus : int32_t
    {
        Unknown = -1, ///< 未知错误
        Success = 0, ///< 默认成功
        DegenerateCurve = 1, ///< 退化的曲线
        DontSupport = 2, ///< 不支持
        InvalidInput = 3, ///< 输入数据错误
        Failed = 4, ///< 通用错误
    };

    class IBodyFactory
    {
    public:
        virtual ~IBodyFactory() = 0;

        /*!
        *@brief 构造圆柱体
        *@param[in] ptBottomCenter 底面圆心
        *@param[in] ptTopCenter 顶面圆心
        *@param[in] dRadius 半径
        *@return 圆柱体
        */
        virtual OwnerPtr<IBody> CreateSolidCylinder(
            const Vector3d &bottomCenter,
            const Vector3d &topCenter, 
            double radius
        )const = 0;
        
        /*!
        *@brief 构造长方体
        *@param[in] coordinate 右手坐标系（原点为长方体顶点）
        *@param[in] dimension  长，宽，高（大于或者等于零）
        *@return 长方体
        */
        virtual OwnerPtr<IBody> CreateSolidCuboid(
            const Coordinate3d &coordinate, 
            const Vector3d &dimension
        )const = 0;

        /*!
        *@brief 构造球体
        *@param[in] center   球心
        *@param[in] unitAxis 单位轴向（平面的法向）
        *@param[in] radius   半径
        *@return 球体
        */
        virtual OwnerPtr<IBody> CreateSphereBody(
            const Vector3d &center,
            const Vector3d &unitAxis,
            double radius
        )const = 0;

        /*!
        *@brief 构造圆锥体
        *@param[in] bottomCenter 底面圆心
        *@param[in] topPos   顶点
        *@param[in] radius   底面半径
        *@return 圆锥体
        */
        virtual OwnerPtr<IBody> CreateConeBody(
            const Vector3d &bottomCenter,
            const Vector3d &topPos,
            double bottomRadius
        )const = 0;

        /*!
        *@brief 构造圆台体
        *@param[in] bottomCenter 底面圆心
        *@param[in] topPos （圆锥的）顶点
        *@param[in] radius 底面半径
        *@param[in] height 圆台高度
        *@return 圆台体
        */
        virtual OwnerPtr<IBody> CreateTruncedConeBody(
            const Vector3d &bottomCenter,
            const Vector3d &topPos,
            double radius,
            double height
        )const = 0;

        /*!
        *@brief 构造圆台体
        *@param[in] bottomCenter 底面圆心
        *@param[in] bottomRadius 底面半径
        *@param[in] topCenter 顶面圆心
        *@param[in] topRadius 顶面半径
        *@return 圆台体
        */
        virtual OwnerPtr<IBody> CreateTruncedConeBody(
            const Vector3d &bottomCenter,
            double bottomRadius,
            const Vector3d &topCenter,
            double topRadius
        )const = 0;

        /*!
        *@brief 构造棱锥体
        *@param[in] apex 顶点
        *@param[in] basePoints 底面多边形顶点
        *@return 棱锥体
        */
        virtual OwnerPtr<IBody> CreatePyramidBody(
            const Vector3d &apex,
            const std::vector<Vector3d> &basePoints
        )const = 0;

        /*!
        *@brief 构造棱台体
        *@param[in] bottomPoints 底面顶点坐标
        *@param[in] topPoints    顶面顶点坐标
        *@param[in] verticesMap  上下面顶点的对应, Vector2i的X分量表示bottomPoints的顶点索引, Y分量topPoints顶点索引, x,y分量构成的序列前后值都是相同或者相邻的顶点索引.
        *@return 棱台体
        */
        virtual OwnerPtr<IBody> CreatePrismBody(
            const std::vector<Vector3d> &bottomPoints,
            const std::vector<Vector3d> &topPoints,
            const std::vector<Vector2i> &verticesMap
        )const = 0;

        /*!
        *@brief 构造椭球体
        *@param[in] pos 椭球体中心点位置
        *@param[in] majorAxis 椭圆长半轴方向
        *@param[in] majorRad 长半轴长度
        *@param[in] minorRad 短半轴长度
        *@return 椭球体
        */
        virtual OwnerPtr<IBody> CreateEllipsoidBody(
            const Vector3d &pos,
            const Vector3d &majorAxis,
            double majorRad,
            double minorRad
        )const = 0;

        /*!
        *@brief 构造椭球体
        *@param[in] center 椭球体中心坐标系
        *@param[in] axisX X轴方向
        *@param[in] axisY Y轴方向
        *@param[in] xRad X半轴方向半径
        *@param[in] yRad Y半轴方向半径
        *@param[in] zRad Z半轴方向半径
        *@param[in] retBody 椭球体
        *@return 错误码
        */
        virtual GeometryErrorCode CreateEllipsoidBody(
            const Vector3d &center,
            const Vector3d &axisX,
            const Vector3d &axisY,
            double xRad,
            double yRad,
            double zRad,
            OwnerPtr<IBody>& retBody
        )const =0;

        /*!
        *@brief 构造圆环体
        *@param[in] pos 圆环体中心位置
        *@param[in] axis 圆环体中心轴方向
        *@param[in] bodyRadius 圆环体半径
        *@param[in] sectionRadius 圆环体截面半径
        *@return 圆环体
        */
        virtual OwnerPtr<IBody> CreateTorusBody(
            const Vector3d &pos,
            const Vector3d &axis,
            double bodyRadius,
            double sectionRadius
        )const = 0;

        /*!
        *@brief 构造棱柱体（正多边形）
        *@param[in] centerPt 正多边形外接圆圆心
        *@param[in] radius 正多边形外接圆半径
        *@param[in] n 正多边形边数
        *@param[in] direction 拉伸方向
        *@param[in] length 拉伸距离，不允许为0，正值为沿拉伸正方向，负值为沿拉伸反方向
        *@return 棱柱体
        */
        virtual OwnerPtr<IBody> CreateRegularPrismBody(
            const Vector3d &centerPt,
            double radius,
            int n,
            const Vector3d &direction,
            double length
        )const = 0;

        /*!
        *@brief 构造椭圆锥体,需保证输入椭圆长半轴方向与中心轴方向垂直
        *@param[in] centerPt 椭圆中心点
        *@param[in] majorAxis 椭圆长半轴方向
        *@param[in] majorRad 椭圆长半轴长度
        *@param[in] minorRad 椭圆短半轴长度
        *@param[in] direction 椭圆锥中心轴方向
        *@param[in] height 椭圆锥高度
        *@return 椭圆锥体
        */
        virtual OwnerPtr<IBody> CreateEllipseConeBody(
            const Vector3d &centerPt,
            const Vector3d &majorAxis,
            double majorRad,
            double minorRad,
            const Vector3d &direction,
            double height
        )const = 0;

        /*!
        *@brief 构造拉伸体
        *@param[in] opFace   面
        *@param[in] unitDirection  拉伸方向
        *@param[in] length  拉伸长度
        *@return 拉伸体
        */
        virtual OwnerPtr<IBody> CreateExtrudeBody(
            const IFace* pFace, 
            const Vector3d&  unitDirection,
            double length
        ) const = 0;

        /*!
        *@brief 构造拉伸体
        *@param[in] coordinate 右手坐标系
        *@param[in] opPolygon  多边形
        *@param[in] unitDirection  拉伸方向
        *@param[in] length  拉伸长度
        *@return 拉伸体
        */
        virtual OwnerPtr<IBody> CreateExtrudeBody(
            const Coordinate3d &coordinate,
            const IPolygon* opPolygon,
            const Vector3d&  unitDirection,
            double length
        )const = 0;

        /*!
        *@brief 构造拉伸体
        *@param[in] coordinate 右手坐标系
        *@param[in] pPolygon  多边形
        *@param[in] unitDirection  拉伸方向
        *@param[in] startOffset    起始端偏移值
        *@param[in] endOfffset     终止端偏移值
        *@param[out] opFaceToPathProfileIndexMap  Face索引与轮廓索引的关系数据
        *@return 拉伸体
        */
        virtual OwnerPtr<IBody> CreateExtrudeBody(
            const Coordinate3d &coordinate,
            const IPolygon *pPolygon,
            const Vector3d&  unitDirection,
            double startOffset,
            double endOfffset,
            OwnerPtr<IExtrudeFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap) const = 0;

        /*!
        *@brief 构造拉伸体(待废弃)
        *@param[in] coordinate 右手坐标系
        *@param[in] pSection  多边形
        *@param[in] unitDirection  拉伸方向
        *@param[in] startOffset    起始端偏移值
        *@param[in] endOfffset     终止端偏移值
        *@param[in] sketchCrvIndices  草图线的唯一序号
        *@return 拉伸体
        */
        virtual OwnerPtr<IBody> CreateExtrudeBody(
            const Coordinate3d& plane,
            const IPolygon* pSection,
            const Vector3d& direction,
            double startOffset,
            double endOffset,
            const std::vector<Int32>& sketchCrvIndices)const = 0;

        /*!
        *@brief 构造拉伸体
        *@param[in] coordinate 右手坐标系
        *@param[in] pSection  多边形
        *@param[in] unitDirection  拉伸方向
        *@param[in] startOffset    起始端偏移值
        *@param[in] endOfffset     终止端偏移值
        *@param[in] sketchCrvIndices  草图线的唯一序号
        *@return 拉伸体
        */
        virtual OwnerPtr<IBody> CreateExtrudeBody(
            IGraphicsNodeIdAsker* pGNodeIdAsker,
            const Coordinate3d& plane,
            const IPolygon* pSection,
            const Vector3d& direction,
            double startOffset,
            double endOffset,
            const std::vector<Int32>& sketchCrvIndices)const = 0;

        /*!
        *@brief     构造沿一串相互连接的空间曲线拉伸的拉伸壳体
        *@param const IPlane *pPlane  草图所在的平面坐标系，拉伸的基准坐标系
        *@param const IPolyCurve *pCurve  拉伸轮廓
        *@param const Vector3d &direction 拉伸方向，不允许平行于基准坐标系XY平面
        *@param double length                   拉伸距离，不能为0
        *@return    拉伸壳体
        */
        virtual OwnerPtr<IBody> CreateExtrudeShellBody(
            const IPlane *pPlane, 
            const IPolyCurve *pCurve,
            const Vector3d &direction,
            double length) const = 0;

        /*!
        *@brief 根据三维空间点列表构建一个平面,垂直平面拉伸成体;
        *@param[in] pointsVec 空间点列表;
        *@param[in] length 拉伸长度;
        *@return IBody  
        */
        virtual OwnerPtr<IBody> CreateExtrudeBodyByPoints(
            const std::vector<Vector3d> &pointsVec,
            double length
         ) const = 0;

        /*!
        *@brief 根据三维空间点列表构建一个平面,垂直平面拉伸成体;需保证点列表共面;
        *@param[in] pointsVec  空间点列表;
        *@param[in] pointsVec  拉伸方向;
        *@param[in] length     拉伸长度;
        *@return 拉伸体;
        */
        virtual OwnerPtr<IBody> CreateExtrudeBodyByPoints(
            const std::vector<Vector3d> &pointsVec,
            const Vector3d &unitDirection, 
            double length
        )const = 0;
        
         /*!
        *@brief 根据三维空间三个点 构建一个圆弧, offset出一个共圆心的新圆弧, 两圆弧形成闭合多边形平面, 垂直平面拉伸成体;
        *@param[in] firstPt   开始点坐标;
        *@param[in] endPt     终点坐标;
        *@param[in] refPt     参考点坐标;
        *@param[in] thickness 实体厚度;
        *@param[in] length    拉伸高度;
        *@return 拉伸体;
        */
        virtual OwnerPtr<IBody> CreateExtrudeBodyByArc(
            const Vector3d &firstPt, 
            const Vector3d &endPt, 
            const Vector3d &ptOnArc,
            double thickness, 
            double height
        )const = 0;

        /// \brief  线框体拉伸成壳体，壳体拉伸成实体
        /// \param[in] pBody  线框体或壳体
        /// \param[in] direction  拉伸方向
        /// \param[in] length  拉伸长度
        /// \param[out] opResultBody  拉伸的壳体或实体
        /// \return 错误码
        virtual GeometryErrorCode CreateExtrudeBody(
            const IBody* pBody,
            const Vector3d& direction,
            double length,
            OwnerPtr<IBody>& opResultBody
        ) const = 0;

        /// \brief  线框体旋转成壳体，壳体旋转成实体
        /// \param[in] pBody   线框体或壳体
        /// \param[in] pAxis3d  带方向的旋转轴
        /// \param[in] revolvedAngle  旋转角度，弧度表示
        /// \param[out] opResultBody  旋转的实体
        /// \return 错误码
        virtual GeometryErrorCode CreateRevolveBody(
            const IBody* pBody,
            const ILine3d* pAxis3d,
            double revolvedAngle,
            OwnerPtr<IBody>& opResultBody
        ) const = 0;

        /*!
        *@brief 构造旋转体
        *@param[in] const Coordinate3d& coordinate  草图和旋转轴所在的平面，草图和旋转轴必须在一个平面上
        *@param[in] const IPolygon* pSection        草图截面
        *@param[in] const ILine2d* pAxis2d        带方向的旋转轴
        *@param[in] double revolvedAngle            旋转角度，弧度表示
        *@return 旋转体
        */
        virtual OwnerPtr<IBody> CreateRevolveBody(
            const Coordinate3d& coordinate, 
            const IPolygon* pSection,
            const ILine2d* pAxis2d, 
            double revolvedAngle
        )const = 0;

        /*!
        *@brief 构造旋转体
        *@param[in] const Coordinate3d& plane  草图和旋转轴所在的平面，草图和旋转轴必须在一个平面上
        *@param[in] const IPolygon* pSection        草图截面
        *@param[in] const ILine2d* pAxis2d        带方向的旋转轴
        *@param[in] double startAngle           起始旋转角度，弧度表示
        *@param[in] double endAngle            终止旋转角度，弧度表示
        *@return 旋转体
        */
        virtual OwnerPtr<IBody> CreateRevolveBody(
            const Coordinate3d& plane,
            const IPolygon* pSection,
            const ILine2d* pAxis2d,
            double startAngle,
            double endAngle
        )const = 0;

        /*!
        *@brief 构造旋转体
        *@param[in] const Coordinate3d& plane  草图和旋转轴所在的平面，草图和旋转轴必须在一个平面上
        *@param[in] const IPolygon* pSection        草图截面
        *@param[in] const ILine2d* pAxis2d        带方向的旋转轴
        *@param[in] double startAngle           起始旋转角度，弧度表示
        *@param[in] double endAngle            终止旋转角度，弧度表示
        *@param[in] sketchCrvIndices  草图线的唯一序号
        *@return 旋转体
        */
        virtual OwnerPtr<IBody> CreateRevolveBody(
            IGraphicsNodeIdAsker* pGNodeIdAsker,
            const Coordinate3d& plane,
            const IPolygon* pSection,
            const ILine2d* pAxis2d,
            double startAngle,
            double endAngle,
            const std::vector<Int32>& sketchCrvIndices
        )const = 0;

        /// \brief  壳体扫掠成实体
        /// \param[in] pBody  扫描轮廓：线框体（wire）或壳体(sheet)
        /// \param[in] pSpine  一组至少G0连接的空间脊线: 线框体(wire)
        /// \param[in] options  扫描选项
        /// \param[out] opResultBody  扫描的实体
        /// \return 错误码
        virtual GeometryErrorCode CreateSweepBody(
            const IBody* pBody,
            const IBody* pSpine,
            const SweepOptions& options,
            OwnerPtr<IBody>& opResultBody
        ) const = 0;

        /*!
        *@brief 构造多段扫描体
        *@param[in] const OwnerPtr<IPolygon>& opSection  草图截面，其局部坐标系确定：Y方向对应路径坐标系的Z轴，Z方向对应扫描路径的切线方向
        *@param[in]  const std::vector<OwnerPtr<ICurve2d>>& opSpines              扫描路径线，目前只支持直线和圆弧
        *@param[in] const Coordinate3d& coordinate         扫描路径线所在的坐标系，路径位于XOY面上
        *@param[out] opSweepFaceToPathProfileIndexMap  Face索引与路径和轮廓索引的关系数据
        *@return 多段扫描体
        */
        virtual OwnerPtr<IBody> CreateSweepBody(
            const OwnerPtr<IPolygon>& opSection,
            const std::vector<OwnerPtr<ICurve2d>>& opSpines,
            const Coordinate3d& coordinate,
            OwnerPtr<ISweepFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap
        )const = 0;

        /*!
        *@brief 构造多段扫描体
        *@param[in]  const OwnerPtr<IPolygon>& opSection              草图截面，其局部坐标系确定：Y方向对应路径坐标系的Z轴，Z方向对应扫描路径的切线方向
        *@param[in]  const std::vector<OwnerPtr<ICurve3d>>& opSpines          扫描路径线
        *@param[in]  refVector   参考方向
        *@param[out] opSweepFaceToPathProfileIndexMap  Face索引与路径和轮廓索引的关系数据
        *@return 多段扫描体
        *@note 使用默认扫描类型SweepType::Perpendicular, 如果需要自定义扫描类型，使用另外一个接口
        */
        virtual OwnerPtr<IBody> CreateSweepBody(
            const OwnerPtr<IPolygon>& opSection,
            const std::vector<const ICurve3d*>& opSpines,
            const Vector3d& refVector,
            OwnerPtr<ISweepFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap
        )const = 0;

        /*!
        *@brief 构造多段扫描体
        *@param[in]  const OwnerPtr<IPolygon>& opSection              草图截面，其局部坐标系确定：Y方向对应路径坐标系的Z轴，Z方向对应扫描路径的切线方向
        *@param[in]  const std::vector<OwnerPtr<ICurve3d>>& opSpines          扫描路径线
        *@param[in]  refVector   参考方向
        *@param[in]  type   扫描类型
        *@param[out] opSweepFaceToPathProfileIndexMap  Face索引与路径和轮廓索引的关系数据
        *@return 多段扫描体
        */
        virtual OwnerPtr<IBody> CreateSweepBody(
            const OwnerPtr<IPolygon>& opSection,
            const std::vector<const ICurve3d*>& opSpines,
            const Vector3d& refVector,
            SweepType type,
            OwnerPtr<ISweepFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap   
        )const = 0;

        /*!
        *@brief 构造多段扫略体(带拓扑命名)
        *@param[in] const IPolygon* opSection,                        草图截面，其局部坐标系确定：Y方向对应路径坐标系的Z轴，Z方向对应扫略路径的切线方向
        *@param[in] const IPolyCurve* pSpines                        扫略路径线，目前只支持直线和圆弧
        *@param[in] const Coordinate3d& coordinate                      扫略路径线所在的坐标系，路径位于XOY面上
        *@param[in] const std::vector<Int32>& sketchCrvIndices          草图线的唯一序号
        *@param[in] const std::vector<Int32>& pathCrvIndices            扫略路径的唯一序号
        *@return 多段扫略体
        */
        virtual OwnerPtr<IBody> CreateSweepBody(
            IGraphicsNodeIdAsker* pGNodeIdAsker,
            const IPolygon* opSection,
            const IPolyCurve* pSpines,
            const Coordinate3d& coordinate,
            const std::vector<Int32>& sketchCrvIndices,
            const std::vector<Int32>& pathCrvIndices
        )const = 0;

        /*!
        *@brief 构造多段扫略体（带拓扑命名）
        *@param[in] IGraphicsNodeIdAsker* pGNodeIdAsker   拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        *@param[in] const IPolygon* opSection,                        草图截面，其局部坐标系确定：Y方向对应路径坐标系的Z轴，Z方向对应扫略路径的切线方向
        *@param[in] const std::vector<const ICurve3d*>& opSpines      扫略路径线，目前只支持直线和圆弧
        *@param[in] const Vector3d& refVector   参考向量
        *@param[in] const std::vector<Int32>& sketchCrvIndices          草图线的唯一序号
        *@param[in] const std::vector<Int32>& pathCrvIndices            扫略路径的唯一序号
        *@return 多段扫略体
        *@note 使用默认扫描类型SweepType::Perpendicular，如果需要自定义扫描类型，请使用另外一个接口
        */
        virtual OwnerPtr<IBody> CreateSweepBody(
            IGraphicsNodeIdAsker* pGNodeIdAsker,
            const IPolygon* opSection,
            const std::vector<const ICurve3d*>& opSpines,
            const Vector3d& refVector,
            const std::vector<Int32>& sketchCrvIndices,
            const std::vector<Int32>& pathCrvIndices
        )const = 0;

        /*!
        *@brief 构造多段扫略体（带拓扑命名）
        *@param[in] IGraphicsNodeIdAsker* pGNodeIdAsker   拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        *@param[in] const IPolygon* opSection,                        草图截面，其局部坐标系确定：Y方向对应路径坐标系的Z轴，Z方向对应扫略路径的切线方向
        *@param[in] const std::vector<const ICurve3d*>& opSpines      扫略路径线，目前只支持直线和圆弧
        *@param[in] const Vector3d& refVector   参考向量
        *@param[in] const std::vector<Int32>& sketchCrvIndices          草图线的唯一序号
        *@param[in] const std::vector<Int32>& pathCrvIndices            扫略路径的唯一序号
        *@param[in] type  扫描类型
        *@return 多段扫略体
        */
        virtual OwnerPtr<IBody> CreateSweepBody(
            IGraphicsNodeIdAsker* pGNodeIdAsker,
            const IPolygon* opSection,
            const std::vector<const ICurve3d*>& opSpines,
            const Vector3d& refVector,
            const std::vector<Int32>& sketchCrvIndices,
            const std::vector<Int32>& pathCrvIndices,
            SweepType type
        )const = 0;

        /*!
        *@brief     由给定拓扑面生成壳体，做深拷贝，默认给定的Face是合法的，不做拓扑多边形位于曲面参数域内的安全检查，如果已知体中的面号，不推荐这个接口。此接口仅用于体的信息不完备只有CFace的情况
        *@param[in] const OwnerPtr<IFace> opFace 拓扑曲面，函数内会做深拷贝
        *@return 壳体
        */
        virtual OwnerPtr<IBody> CreateShell(
            const IFace* pFace
        )const = 0;

        /*!
        *@brief     由给定的曲面和参数域（Loop定义的）创建一个Shell
        *@param[in] const ISurface* pSurface         曲面，函数内会做深拷贝
        *@param[in] const IPolyCurve* pPolyCurve                环，指定参数域，函数内会做深拷贝
        *@return 壳体
        */
        virtual OwnerPtr<IBody> CreateShell(
            const ISurface* pSurface,
            const IPolyCurve* pPolyCurve
        )const = 0;

        /*!
        *@brief     由给定的曲面和参数域（Polygon定义的）创建一个Shell
        *@param[in] const ISurface* pSurface         曲面，函数内会做深拷贝
        *@param[in] const IPolygon* pPolygon          多边形，指定参数域，函数内会做深拷贝 
        *@return 壳体
        */
        virtual OwnerPtr<IBody> CreateShell(
            const ISurface* pSurface,
            const IPolygon* pPolygon
        )const = 0;

        /*!
        *@brief     由给定的曲面和参数域（Polygon定义的）创建一个Shell
        *@param[in] const ISurface* pSurface          曲面，函数内会做深拷贝
        *@param[in] const IPolygon* pPolygon          多边形，指定参数域，函数内会做深拷贝
        *@param[in] isSameDir                         = true face的方向是否与surface中一致.
                                                      后续会使用ggp的另外一个接口，暂时预留参数
        *@param[in] bool isStichShell = false         是否缝合pResultBody与保留面的重合边，默认为false。注意保留面之间重合边默认就是缝合的
        *@return 壳体
        */
        virtual OwnerPtr<IBody> CreateShell(
            const ISurface* pSurface,
            const IPolygon* pPolygon,
            bool isSameDir,
            bool isStichShell
        )const = 0;

        /// \brief  由给定实体及需要保留的面序号，生成保留的面组成的壳体，做深拷贝
        /// \param pSourceBody    原实体
        /// \param faceIndex      要求保留的面集合，函数内会对该参数做修改，排序，去重等
        /// \return 壳体
        virtual OwnerPtr<IBody> CreateShell(const IBody* pSourceBody, const std::vector<int>& faceIndex) const = 0;

        /// \brief  由给定一个或多个三维多段线生成壳体
        /// \param[in] pPolyCurve3ds  每个三维多段线要求有序的首尾连续且封闭，三维边线两两之间不相交并且无自交
        /// \param[out] resultBody  构造的壳体
        /// \return 构造壳体错误类型
        virtual ShellErrorStatus CreateShell(const std::vector<const IPolyCurve3d*>& pPolyCurve3ds, OwnerPtr<IBody>& resultBody) const = 0;

        /*!
        *@brief 构造沿一串相互连接的空间曲线扫描的扫描壳体
        *@param[in] const std::vector<OwnerPtr<ICurve2d>>& connectedCurves   首尾相连的二维曲线
        *@param[in] const std::vector<const ICurve3d*>& pCurve3ds    一组至少G0连接的空间脊线
        *@param[in] const Vector3d& firstRefVec        第一段的参考方向（ST_Perpendicular类型）
        *@return 扫描体
        */
        virtual OwnerPtr<IBody> CreateShellBody(
            const std::vector<OwnerPtr<ICurve2d>>& connectedCurves,  
            const std::vector<const ICurve3d*>& pCurve3ds,
            const Vector3d& firstRefVec
        )const = 0;

        /// \brief  根据给定点坐标构造单点体
        /// \param[in] point  点坐标
        /// \param[out] opAcornBody  创建的单点体
        /// \return 错误码
        virtual GeometryErrorCode MakeAcornBody(const Vector3d& point, OwnerPtr<IBody>& opAcornBody) const = 0;

        /// \brief  由一组拓扑边构造线框体
        /// \param[in] edges  输入边集合
        /// \param[out] opWireBody  创建的wirebody
        /// \return 错误码
        virtual GeometryErrorCode MakeWireBody(const std::vector<const IEdge*>& edges, OwnerPtr<IBody>& opWireBody) const = 0;

        /// \brief  由一组三维多段线构造线框体
        /// \param[in] pPolyCurve3ds  一组三维多段线
        /// \param[out] opWireBody  创建的wirebody
        /// \return 错误码
        virtual GeometryErrorCode MakeWireBody(const std::vector<const IPolyCurve3d*>& pPolyCurve3ds, OwnerPtr<IBody>& opWireBody) const = 0;

        /// \brief  由给定线框体构造壳体，要求线框是闭合的
        /// \param[in] pWireBody  线框体
        /// \param[out] opSheetBody  创建的壳体
        /// \return 错误码
        virtual GeometryErrorCode MakeSheetBody(const IBody* pWireBody, OwnerPtr<IBody>& opSheetBody) const = 0;

        /*!
        *@brief 由给定的底平面和顶平面创建一个融合体（带拓扑命名）
        *@param[in] const Coordinate3d& bottomPlane                                 底平面坐标系
        *@param[in] const IPolygon*  pBottomSection                               底平面轮廓，可多个环
        *@param[in] const Coordinate3d& topPlane                                    顶平面坐标系
        *@param[in] const IPolygon*  pTopSection                                  顶平面轮廓，可多个环
        *@param[in] const std::vector<std::vector<int>> &topSketchCurveIndices      顶面草图线的唯一序号
        *@param[in] const std::vector<std::vector<int>> &bottomSketchCurveIndices   底面草图线的唯一序号
        *@param[in] const std::vector<std::vector<Vector2i>> &vertices_map          上下面顶点的对应, 是一个二维数组：外面的数组索引是两个轮廓的环的索引；里面的数组中，CVector2i的X分量表示底面的环的顶点索引, Y分量顶面的环的顶点索引,
        x,y分量构成的序列前后值都是相同或者相邻的顶点索引；约定底部轮廓的环的顶点索引从0开始（顶部轮廓的环的顶点索引是可以不从0开始的）
        比如底部轮廓的第一个环上有4个点，顶部轮廓的第一个环上有3个点，第一个环合法的定点map可以是(0,0), (1,0), (2,1), (3,2)；当然也可以是(0,2), (1,0), (2,0), (3,1)等等
        *@return 融合体
        */
        virtual OwnerPtr<IBody> CreateBlendBody(
            IGraphicsNodeIdAsker* pGNodeIdAsker,
            const Coordinate3d& bottomPlane,
            const IPolygon*  pBottomSection,
            const Coordinate3d& topPlane,
            const IPolygon*  pTopSection,
            const std::vector<std::vector<int>> &topSketchCurveIndices,
            const std::vector<std::vector<int>> &bottomSketchCurveIndices,
            const std::vector<std::vector<Vector2i>> & vertices_map
        )const = 0;

        /// \brief 由给定的底平面和顶平面创建一个融合体（不带拓扑命名，仅返回拓扑关系Map）
        ///
        /// \param[in] bottomPlane            底平面坐标系
        /// \param[in] pBottomSection         底平面轮廓，可多个环
        /// \param[in] topPlane               顶平面坐标系
        /// \param[in] pTopSection            顶平面轮廓，可多个环
        /// \param[in] vertices_map           顶底草图截面顶点的对应, 是一个二维数组：外面的数组索引是两个轮廓的环的索引；里面的数组中，Vector2i的X分量表示底面的环的顶点索引, Y分量顶面的环的顶点索引,
        ///                                   x,y分量构成的序列前后值都是相同或者相邻的顶点索引；约定底部轮廓的环的顶点索引从0开始（顶部轮廓的环的顶点索引是可以不从0开始的）
        ///                                   比如底部轮廓的第一个环上有4个点，顶部轮廓的第一个环上有3个点，第一个环合法的定点map可以是(0,0), (1,0), (2,1), (3,2)；当然也可以是(0,2), (1,0), (2,0), (3,1)等等
        /// \param[out] opFaceToPathProfileIndexMap   Face索引与顶底截面轮廓索引的关系数据
        /// \return 融合体
        virtual OwnerPtr<IBody> CreateBlendBody(
            const Coordinate3d& bottomPlane,
            const IPolygon*  pBottomSection,
            const Coordinate3d& topPlane,
            const IPolygon*  pTopSection,
            const std::vector<std::vector<Vector2i>> & vertices_map,
            OwnerPtr<IBlendFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap
        )const = 0;

        /// \brief  由顶面和底面轮廓生成放样融合体
        ///         由于需要顶点IVertex的匹配关系，所以需要开启拓扑点生成之后这个接口才有效（可以设置gbmp_gcmp_behavior_config的配置EnableVertexGeneration不为0）
        /// \param[in] pTopBody  顶面轮廓（壳体或线框体）
        /// \param[in] pBottomBody  底面轮廓（壳体或线框体，需要和顶面轮廓类型一致）
        /// \param[in] options  顶面和底面放样融合选项
        ///  options.DistEpsilon  距离容差
        ///  options.Type  放样类型，目前支持Default类型（不调整轮廓位置）和Perpendicular类型（将轮廓调整为和脊线垂直）
        ///  options.Spine  脊线，可以为默认空指针，为空时放样类型不起作用
        ///  options.LoftVerticesMap  两截面顶点匹配关系，如果顶面和底面顶点数相同，可仅指定起始顶点匹配关系
        /// \param[out] opResultBody  创建的放样融合体
        /// \return 错误码
        virtual GeometryErrorCode CreateBlendBody(
            const IBody* pTopBody,
            const IBody* pBottomBody,
            const gcmp::BlendOptions& options,
            OwnerPtr<IBody>& opResultBody
        )const = 0;

        /*!
        *@brief     algloft.h->CSpineLoft的封装，带脊线的放样体
        *@param[in] IGraphicsNodeIdAsker* pGNodeIdAsker   拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        *@param[in]  const IPolygon* pBottomSection       放样末端曲线polygon，不会被改变，内不会拷贝一份
        *@param[in]  const IPolygon* pTopSection     放样首端polygon，不会被改变，内不会拷贝一份        
        *@param[in]  const std::vector<const ICurve3d*>& spine            脊线
        *@param[in]  const Vector3d& referenceVector  参考向量
        *@param[in] const std::vector<std::vector<int>> &topSketchCurveIndices      顶面草图线的唯一序号
        *@param[in] const std::vector<std::vector<int>> &bottomSketchCurveIndices   底面草图线的唯一序号
        *@param[in]  const std::vector<std::vector<Vector2i>>& verticesMap      点对应关系
        vertices_map 上下面顶点的对应, 是一个二维数组, 必须封闭：外面的数组索引是两个轮廓的环的索引；里面的数组中，CVector2i的X分量表示底面的环的顶点索引, Y分量顶面的环的顶点索引,
        x,y分量构成的序列前后值都是相同或者相邻的顶点索引；比如底部轮廓的第一个环上有4个点，顶部轮廓的第一个环上有3个点，第一个环合法的定点map可以是(0,0), (1,0), (2,1), (3,2), (0,0)；当然也可以是(0,2), (1,0), (2,0), (3,1),(0,2)等等
        *@return 放样融合体
        *@note 该接口使用默认放样类型Loft::Perpendicular,如果希望自定义放样类型，请使用另外一个接口
        */
        virtual OwnerPtr<IBody> CreateSweptLoftBody(
            IGraphicsNodeIdAsker*                    pGNodeIdAsker,
            const IPolygon*                           pBottomSection,
            const IPolygon*                           pTopSection,
            const std::vector<const ICurve3d*>&       spines,
            const Vector3d&                             referenceVector,
            const std::vector<std::vector<int>>&        topSketchCurveIndices,
            const std::vector<std::vector<int>>&        bottomSketchCurveIndices,
            const std::vector<std::vector<Vector2i>>&   vertices_map
        )const = 0;

        /*!
        *@brief     algloft.h->CSpineLoft的封装，带脊线的放样体
        *@param[in] IGraphicsNodeIdAsker* pGNodeIdAsker   拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        *@param[in]  const IPolygon* pBottomSection       放样末端曲线polygon，不会被改变，内不会拷贝一份
        *@param[in]  const IPolygon* pTopSection     放样首端polygon，不会被改变，内不会拷贝一份
        *@param[in]  const std::vector<const ICurve3d*>& spine            脊线
        *@param[in]  const Vector3d& referenceVector  参考向量
        *@param[in] const std::vector<std::vector<int>> &topSketchCurveIndices      顶面草图线的唯一序号
        *@param[in] const std::vector<std::vector<int>> &bottomSketchCurveIndices   底面草图线的唯一序号
        *@param[in]  const std::vector<std::vector<Vector2i>>& verticesMap      点对应关系
        vertices_map 上下面顶点的对应, 是一个二维数组, 必须封闭：外面的数组索引是两个轮廓的环的索引；里面的数组中，CVector2i的X分量表示底面的环的顶点索引, Y分量顶面的环的顶点索引,
        x,y分量构成的序列前后值都是相同或者相邻的顶点索引；比如底部轮廓的第一个环上有4个点，顶部轮廓的第一个环上有3个点，第一个环合法的定点map可以是(0,0), (1,0), (2,1), (3,2), (0,0)；当然也可以是(0,2), (1,0), (2,0), (3,1),(0,2)等等
        *@param[in] LoftType type 放样类型
        *@return 放样融合体
        */
        virtual OwnerPtr<IBody> CreateSweptLoftBody(
            IGraphicsNodeIdAsker*                    pGNodeIdAsker,
            const IPolygon*                           pBottomSection,
            const IPolygon*                           pTopSection,
            const std::vector<const ICurve3d*>&       spines,
            const Vector3d&                             referenceVector,
            const std::vector<std::vector<int>>&        topSketchCurveIndices,
            const std::vector<std::vector<int>>&        bottomSketchCurveIndices,
            const std::vector<std::vector<Vector2i>>&   vertices_map,
            LoftType type
        )const = 0;

        /*!
        *@brief  algloft.h->CSpineLoft的封装，带脊线的放样体
                 Coordinate应满足:
                     1、原点应与路径的始末点重合
                     2、Z轴与路径的始末切矢的夹角theta<(90-Constants::ANGLE_EPS)
                     3、为单位正交右手系
                 Polygon应满足:
                     1、polygon在Coordinate的XOY平面上
                     2、第一个环是逆时针的 且polygon是单连通的，不支持多连通polygon
        *@param[in] IGraphicsNodeIdAsker* pGNodeIdAsker   拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        *@param[in]  const IPolygon* pBottomSection       放样末端曲线polygon，不会被改变，内不会拷贝一份
        *@param[in]  const IPolygon* pTopSection          放样首端polygon，不会被改变，内不会拷贝一份
        *@param[in]  const Coordinate3d& bottomCoordinate         首端起始坐标系
        *@param[in]  const Coordinate3d& topCoordinate            末端终止坐标系
        *@param[in]  const std::vector<const ICurve3d*>& spine            脊线
        *@param[in] const std::vector<std::vector<int>> &bottomSketchCurveIndices   底面草图线的唯一序号
        *@param[in] const std::vector<std::vector<int>> &topSketchCurveIndices      顶面草图线的唯一序号
        *@param[in]  const std::vector<std::vector<Vector2i>>& vertices_map      点对应关系
        vertices_map 上下面顶点的对应, 是一个二维数组, 必须封闭：外面的数组索引是两个轮廓的环的索引；里面的数组中，CVector2i的X分量表示底面的环的顶点索引, Y分量顶面的环的顶点索引,
        x,y分量构成的序列前后值都是相同或者相邻的顶点索引；比如底部轮廓的第一个环上有4个点，顶部轮廓的第一个环上有3个点，第一个环合法的定点map可以是(0,0), (1,0), (2,1), (3,2), (0,0)；当然也可以是(0,2), (1,0), (2,0), (3,1),(0,2)等等
        *@return 放样融合体
        */
        virtual OwnerPtr<IBody> CreateSweptLoftBody(
            IGraphicsNodeIdAsker*                    pGNodeIdAsker,
            const IPolygon*                           pBottomSection,
            const IPolygon*                           pTopSection,
            const Coordinate3d&                       bottomCoordinate,
            const Coordinate3d&                       topCoordinate,
            const std::vector<const ICurve3d*>&       spines,
            const std::vector<std::vector<int>>&        bottomSketchCurveIndices,
            const std::vector<std::vector<int>>&        topSketchCurveIndices,
            const std::vector<std::vector<Vector2i>>&   vertices_map
        )const = 0;

        /// \brief  由多截面轮廓生成放样体
        /// \param[in] pBodies  截面轮廓（线框体或壳体，需要类型相同）
        /// \param[in] options  多截面放样选项
        /// \param[out] opResultBody  创建的放样体
        /// \return 错误码
        virtual GeometryErrorCode CreateMultiSectionLoftBody(
            const std::vector<const IBody*>& pBodies,
            const MultiSectionLoftOptions& options,
            OwnerPtr<IBody>& opResultBody
        )const = 0;

        /// \brief 创建多截面放样体（使用引导线、自动计算顶点匹配关系）
        ///
        /// 可参考https://km.glodon.com/pages/viewpage.action?pageId=37652643
        /// \param[out] pGraphicsNodeIdAsker  拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        /// \param[in]  planes                截面坐标系
        /// \param[in]  sections              截面多边形
        /// \param[in]  guides                引导线
        /// \param[in]  isDevidedByGuideCurve 引导线是否分割面(引导线是否为边线)
        /// \param[in]  mode                  顶点匹配模式
        /// \param[in]  minSegmentLength      极小段距离(参考值1)
        /// \param[in]  distEpsilon           距离容差(参考值Constants::LENGTH_EPS)
        /// \param[out] pErrorCode            错误码
        /// \param[out] opFaceToPathProfileIndexMap  Face索引与两侧截面轮廓索引的关系数据
        /// \return 多截面放样体
        virtual OwnerPtr<IBody> CreateMultiSectionLoftBody(
            IGraphicsNodeIdAsker*                  pGraphicsNodeIdAsker,
            const std::vector<Coordinate3d>&       planes,
            const std::vector<const IPolygon*>&    sections,
            const std::vector<const ICurve3d*>&    guides,
            bool                                   isDevidedByGuideCurve,
            const MultiSectionLoftVertexMatchMode& mode,
            double                                 minSegmentLength,
            double                                 distEpsilon,
            MultiSectionLoftErrorCode*             pErrorCode,
            OwnerPtr<IMultiSectionLoftFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap
        )const = 0;

        /// \brief 创建多截面放样体（使用引导线、指定顶点匹配关系）
        ///
        /// 可参考https://km.glodon.com/pages/viewpage.action?pageId=37652643
        /// \param[out] pGraphicsNodeIdAsker  拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        /// \param[in]  planes                截面坐标系
        /// \param[in]  sections              截面多边形
        /// \param[in]  guides                引导线
        /// \param[in]  isDevidedByGuideCurve 引导线是否分割面(引导线是否为边线)
        /// \param[in]  verticesMap           顶点匹配关系
        /// verticesMap 截面顶点匹配关系, 是一个二维数组, 必须封闭：
        /// 外面的数组索引是各组匹配关系的索引；
        /// 里面的数组索引是各个轮廓的环的索引；
        /// 里面的数组的值是相同或者相邻的顶点索引；
        /// 比如底部轮廓的第一个环上有3个点，中部轮廓的第一个环上有3个点，顶部轮廓的第一个环上有3个点，
        /// 第一个环合法的定点map可以是(0,0,0), (1,1,1), (2,2,2), (0,0,0)；
        /// 当然也可以是(0,1,0), (1,2,1), (2,0,2), (0,1,0)等等；
        /// \param[in]  minSegmentLength      极小段距离(参考值1)
        /// \param[in]  distEpsilon           距离容差(参考值Constants::LENGTH_EPS)
        /// \param[out] pErrorCode            错误码
        /// \param[out] opFaceToPathProfileIndexMap  Face索引与两侧截面轮廓索引的关系数据
        /// \return 多截面放样体
        virtual OwnerPtr<IBody> CreateMultiSectionLoftBody(
            IGraphicsNodeIdAsker*                pGraphicsNodeIdAsker,
            const std::vector<Coordinate3d>&     planes,
            const std::vector<const IPolygon*>&  sections,
            const std::vector<const ICurve3d*>&  guides,
            bool                                 isDevidedByGuideCurve,
            const std::vector<std::vector<int>>& verticesMap,
            double                               minSegmentLength,
            double                               distEpsilon,
            MultiSectionLoftErrorCode*           pErrorCode,
            OwnerPtr<IMultiSectionLoftFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap
        )const = 0;

        /// \brief 创建多截面放样体（使用引导线、闭合点）
        ///
        /// 可参考https://km.glodon.com/pages/viewpage.action?pageId=37652643
        /// \param[out] pGraphicsNodeIdAsker  拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        /// \param[in]  planes                截面坐标系
        /// \param[in]  sections              截面多边形
        /// \param[in]  guides                引导线
        /// \param[in]  isDevidedByGuideCurve 引导线是否分割面(引导线是否为边线)
        /// \param[in]  closedPoints          闭合点
        /// closedPoints 闭合点, 是一个一维数组：
        /// 数组索引是各个轮廓的环的索引；
        /// 数组的值是轮廓的环上顶点索引和顶点参数的数值对；
        /// 比如底部轮廓的第一个环上有3个点，中部轮廓的第一个环上有3个点，顶部轮廓的第一个环上有3个点，
        /// 合法的闭合点可以是(0,0.0), (0,0.0), (0,0.0)；
        /// 当然也可以是(0,0.0), (1,0.0), (2,0.0)等等；
        /// \param[in]  mode                  顶点匹配模式
        /// \param[in]  minSegmentLength      极小段距离(参考值1)
        /// \param[in]  distEpsilon           距离容差(参考值Constants::LENGTH_EPS)
        /// \param[out] pErrorCode            错误码
        /// \param[out] opFaceToPathProfileIndexMap  Face索引与两侧截面轮廓索引的关系数据
        /// \return 多截面放样体
        virtual OwnerPtr<IBody> CreateMultiSectionLoftBody(
            IGraphicsNodeIdAsker*                      pGraphicsNodeIdAsker,
            const std::vector<Coordinate3d>&           planes,
            const std::vector<const IPolygon*>&        sections,
            const std::vector<const ICurve3d*>&        guides,
            bool                                       isDevidedByGuideCurve,
            const std::vector<std::pair<int, double>>& closedPoints,
            const MultiSectionLoftVertexMatchMode&     mode,
            double                                     minSegmentLength,
            double                                     distEpsilon,
            MultiSectionLoftErrorCode*                 pErrorCode,
            OwnerPtr<IMultiSectionLoftFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap
        )const = 0;

        /// \brief 创建多截面放样体（自动计算顶点匹配关系）
        ///
        /// 可参考https://km.glodon.com/pages/viewpage.action?pageId=37652643
        /// \param[out] pGraphicsNodeIdAsker   拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        /// \param[in]  planes                 截面坐标系
        /// \param[in]  sections               截面多边形
        /// \param[in]  mode                   顶点匹配模式
        /// \param[in]  isLinear               侧边是否生成为直线
        /// \param[in]  minSegmentLength       极小段距离(参考值1)
        /// \param[in]  distEpsilon            距离容差(参考值Constants::LENGTH_EPS)
        /// \param[out] pErrorCode             错误码
        /// \param[out] opFaceToPathProfileIndexMap  Face索引与两侧截面轮廓索引的关系数据
        /// \return  多截面放样体
        virtual OwnerPtr<IBody> CreateMultiSectionLoftBody(
            IGraphicsNodeIdAsker*                  pGraphicsNodeIdAsker,
            const std::vector<Coordinate3d>&       planes,
            const std::vector<const IPolygon*>&    sections,
            const MultiSectionLoftVertexMatchMode& mode,
            bool                                   isLinear,
            double                                 minSegmentLength,
            double                                 distEpsilon,
            MultiSectionLoftErrorCode*             pErrorCode,
            OwnerPtr<IMultiSectionLoftFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap
        )const = 0;

        /// \brief 创建多截面放样体（使用顶点匹配关系）
        ///
        /// 可参考https://km.glodon.com/pages/viewpage.action?pageId=37652643
        /// \param[out] pGraphicsNodeIdAsker    拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        /// \param[in]  planes                  截面坐标系
        /// \param[in]  sections                截面多边形
        /// \param[in]  verticesMap             顶点匹配关系
        /// verticesMap 截面顶点匹配关系, 是一个二维数组, 必须封闭：
        /// 外面的数组索引是各组匹配关系的索引；
        /// 里面的数组索引是各个轮廓的环的索引；
        /// 里面的数组的值是相同或者相邻的顶点索引；
        /// 比如底部轮廓的第一个环上有3个点，中部轮廓的第一个环上有3个点，顶部轮廓的第一个环上有3个点，
        /// 第一个环合法的定点map可以是(0,0,0), (1,1,1), (2,2,2), (0,0,0)；
        /// 当然也可以是(0,1,0), (1,2,1), (2,0,2), (0,1,0)等等；
        /// \param[in]  isLinear                侧边是否生成为直线
        /// \param[in]  minSegmentLength        极小段距离(参考值1)
        /// \param[in]  distEpsilon             距离容差(参考值Constants::LENGTH_EPS)
        /// \param[out] pErrorCode              错误码
        /// \param[out] opFaceToPathProfileIndexMap  Face索引与两侧截面轮廓索引的关系数据
        /// \return 多截面放样体
        virtual OwnerPtr<IBody> CreateMultiSectionLoftBody(
            IGraphicsNodeIdAsker*                pGraphicsNodeIdAsker,
            const std::vector<Coordinate3d>&     planes,
            const std::vector<const IPolygon*>&  sections,
            const std::vector<std::vector<int>>& verticesMap,
            bool                                 isLinear,
            double                               minSegmentLength,
            double                               distEpsilon,
            MultiSectionLoftErrorCode*           pErrorCode,
            OwnerPtr<IMultiSectionLoftFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap
        )const = 0;

        /// \brief 创建多截面放样体（使用闭合点）
        ///
        /// 可参考https://km.glodon.com/pages/viewpage.action?pageId=37652643
        /// \param[out] pGraphicsNodeIdAsker    拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        /// \param[in]  planes                  截面坐标系
        /// \param[in]  sections                截面多边形
        /// \param[in]  closedPoints            闭合点
        /// closedPoints 闭合点, 是一个一维数组：
        /// 数组索引是各个轮廓的环的索引；
        /// 数组的值是轮廓的环上顶点索引和顶点参数的数值对；
        /// 比如底部轮廓的第一个环上有3个点，中部轮廓的第一个环上有3个点，顶部轮廓的第一个环上有3个点，
        /// 合法的闭合点可以是(0,0.0), (0,0.0), (0,0.0)；
        /// 当然也可以是(0,0.0), (1,0.0), (2,0.0)等等；
        /// \param[in]  mode                    顶点匹配模式
        /// \param[in]  isLinear                侧边是否生成为直线
        /// \param[in]  minSegmentLength        极小段距离(参考值1)
        /// \param[in]  distEpsilon             距离容差(参考值Constants::LENGTH_EPS)
        /// \param[out] pErrorCode              错误码
        /// \param[out] opFaceToPathProfileIndexMap  Face索引与两侧截面轮廓索引的关系数据
        /// \return 多截面放样体
        virtual OwnerPtr<IBody> CreateMultiSectionLoftBody(
            IGraphicsNodeIdAsker*                      pGraphicsNodeIdAsker,
            const std::vector<Coordinate3d>&           planes,
            const std::vector<const IPolygon*>&        sections,
            const std::vector<std::pair<int, double>>& closedPoints,
            const MultiSectionLoftVertexMatchMode&     mode,
            bool                                       isLinear,
            double                                     minSegmentLength,
            double                                     distEpsilon,
            MultiSectionLoftErrorCode*                 pErrorCode,
            OwnerPtr<IMultiSectionLoftFaceToPathProfileIndexMap>& opFaceToPathProfileIndexMap
        )const = 0;

        /// \brief 由给定的屋顶边界线轮廓和坡度角度等参数创建一个屋顶（带拓扑命名）
        ///
        /// \param[in]  plane                                       //屋顶边界线坐标系
        /// \param[in]  pSection                                    //屋顶边界线轮廓，支持多个环
        /// \param[in]  inAngles                                    //屋顶每条边界线的坡度角度
        /// \param[in]  inHeight                                    //屋顶每条边界线与屋顶基准的高度偏移
        /// \param[out] pErrorMessage                               //屋顶造型错误信息
        /// \param[in]  inEaveMode                                  //屋顶屋檐的椽截面类型
        /// \param[in]  inFascia                                    //屋顶屋檐的封檐带深度
        /// \param[in]  sketchCrvIndices                            //屋顶每条边界线对应草图索引，用于拓扑命名
        /// \param[in]  inSlopeArrows                               //屋顶边界线对应坡度箭头数据
        /// \return 屋顶
        virtual OwnerPtr<IBody> CreateRoofBody(
            const Coordinate3d& plane,
            const IPolygon* pSection,
            const std::vector<double>& inAngles,
            const std::vector<double>& inHeights,
            double inThickness,
            std::wstring* pErrorMessage,
            int inEaveMode = 0,
            double inFascia = 0.0,
            const std::vector<Int32>& sketchCrvIndices = std::vector<Int32>(),
            const std::vector<SlopeArrowData>& inSlopeArrows = std::vector<SlopeArrowData>()
        )const = 0;

        /// \brief 构造螺旋体
        /// \param pGraphicsNodeIdAsker 拓扑命名查询器        
        /// \param pSection             草图截面,不同于扫描，其Y方向始终对应螺旋线坐标系的Z轴
        /// \param sketchCrvIndices     草图线的唯一序号
        /// \param coordinate           螺旋线路径所在的局部坐标系
        /// \param spiralRadiusStart    螺旋线路径的起始半径, 必须大于0
        /// \param spiralRadiusEnd      螺旋线路径的终止半径, 必须大于0
        /// \param spiralAngle          螺旋角度，弧度表示，必须大于0
        /// \param height               螺旋线路径的高度，原则上如果是等半径螺旋，高度不能为0（这种情形应该用回转体来做）
        /// \param clockwise            旋转方向, true : 顺时针, false : 逆时针
        /// \return 螺旋体
        virtual OwnerPtr<IBody> CreateSpiralBody(
            IGraphicsNodeIdAsker*         pGraphicsNodeIdAsker,
            const IPolygon*               pSection,
            const std::vector<Int32>&     sketchCrvIndices,
            const Coordinate3d&           coordinate,
            double                        spiralRadiusStart,
            double                        spiralRadiusEnd,
            double                        spiralAngle,
            double                        height,
            bool                          clockwise
        ) const = 0;

        /*!
        *@brief 对壳体ShellBody(由一个或多个Face组成，不封闭)进行加厚
        *@param[in] const IBody* pShellBody                                        //待加厚的壳体
        *@param[in] double dThickness                                               //厚度（正值表示向外偏置，负值表示向内偏置）
        *@return 加厚的实体
        */
        virtual OwnerPtr<IBody> ThickenShellBody(
            const IBody* pShellBody,
            double dThickness
        ) const = 0;

        /*!
        *@brief  创建mesh
        *@param[in] const std::vector<Vector3d>& vertices        顶点的数组
        *@param[in] const std::vector<Vector3d>& vertexNormals   顶点法向的数组
        *@param[in] const std::vector<Vector2d>& vertexUVs             纹理坐标的数组
        *@param[in] const std::vector<int>& triangleVertexIndices  顶点索引，每三个索引一组作为三角片
        *@param[in] const std::vector<int>& triangleVertexNormalIndices   顶点法向索引，每三个索引一组作为三角片
        *@param[in] const std::vector<int>& triangleVertexUVIndices   纹理坐标的索引，每三个索引一组作为三角片
        *@return OwnerPtr<IMesh>
        */
        virtual OwnerPtr<IMesh> CreateMesh(const std::vector<Vector3d>& vertices, 
                                           const std::vector<Vector3d>& vertexNormals,
                                           const std::vector<Vector2d>& vertexUVs,
                                           const std::vector<int>& triangleVertexIndices,
                                           const std::vector<int>& triangleVertexNormalIndices,
                                           const std::vector<int>& triangleVertexUVIndices)const = 0;
        /*!
       *@brief   读取读取obj文件到IMesh（包括几何结构、纹理、法向量）
       *@param[in] filePath 读取的obj文件路径
       *@return OwnerPtr<IMesh>
       */
        virtual OwnerPtr<IMesh>  ReadObjTriMesh(const std::wstring& filePath)const =0;

        /// \brief  构造土方放坡体
        /// \param  pPlane               平面
        /// \param  pPolygon             下底面轮廓
        /// \param  height               高度
        /// \param  widths               每条边的放坡宽度,存储的对象个数应该与pPolygon里所有边的数目总和一样（所有polycurve里的所有曲线）
        /// \return 土方放坡体
        virtual OwnerPtr<IBody> CreateEarthworkSlope(const IPlane* pPlane, const IPolygon* pPolygon, double height, const std::vector<double>& widths) const = 0;

        /// \brief  构造集水坑附着体（创建集水坑附着体专门为BIMMAKE的集水坑附着使用，附着规则与一般的墙体附着规则不同）
        ///         当目标面边界既投影不到附着面，附着面侧面又延伸不到目标面时，集水坑附着能够附着成功（一般墙体附着失败））
        ///         该接口不支持编码编号
        /// \param  pBodyToAttach              附着前的体
        /// \param  faceIndexToAttach          面在待附着体里的索引，该面将会沿着给定方向，附着到给定目标壳体
        /// \param  targetShellBodys           附着的目标壳体集
        /// \param  direction                  附着方向
        /// \return 新生成的附着后的形体
        virtual OwnerPtr<IBody> CreateSumpAttachment(const IBody* pBodyToAttach, int faceIndexToAttach, const std::vector<const IBody*>& targetShellBodys, const Vector3d& direction) const = 0;

        /// \brief  构造附着体
        /// \param  pBodyToAttach              附着前的体
        /// \param  faceIndexToAttach          面在待附着体里的索引，该面将会沿着给定方向，附着到给定目标壳体
        /// \param  pTargetShellBody           附着的目标壳体
        /// \param  direction                  附着方向
        /// \param  pGraphicsNodeIdAsker       拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        /// \param  pTargetShellBodyAuxKey     关于目标壳体的、并协助生成拓扑命名的辅助值。如果不提供，同一个体经过多次附着之后，生成新体的边面可能存在重号的可能
        /// \return 新生成的附着后的形体
        virtual OwnerPtr<IBody> CreateAttachment(const IBody* pBodyToAttach, int faceIndexToAttach, const IBody* pTargetShellBody, 
            const Vector3d& direction, IGraphicsNodeIdAsker* pGraphicsNodeIdAsker, const int* pTargetShellBodyAuxKey) const = 0;

        /// \brief  构造附着体
        /// \param  pBodyToAttach              附着前的体
        /// \param  faceIndexToAttach          面在待附着体里的索引，该面将会沿着给定方向，附着到给定目标壳体
        /// \param  pTargetShellBody           附着的目标壳体
        /// \param  direction                  附着方向
        /// \param  pGraphicsNodeIdAsker       拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        /// \return 新生成的附着后的形体
        GCMP_OBSOLETE_API(2021/12/01, IBodyFactory::CreateAttachment(const IBody*, int, const IBody*, const Vector3d&, IGraphicsNodeIdAsker*, const int*))
        virtual OwnerPtr<IBody> CreateAttachment(const IBody* pBodyToAttach, int faceIndexToAttach, const IBody* pTargetShellBody, const Vector3d& direction, IGraphicsNodeIdAsker* pGraphicsNodeIdAsker) const = 0;

        /// \brief  多目标面构造附着体
        /// \param  pBodyToAttach              附着前的体
        /// \param  faceIndexToAttach          面在待附着体里的索引，该面将会沿着给定方向，附着到给定目标壳体
        /// \param  targetShellBodys           附着的目标壳体集
        /// \param  direction                  附着方向
        /// \param  pGraphicsNodeIdAsker       拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        /// \param  pTargetShellBodyAuxKeys    关于目标壳体的、并协助生成拓扑命名的辅助值。如果不提供，同一个体经过多次附着之后，生成新体的边面可能存在重号的可能
        /// \return 新生成的附着后的形体
        virtual OwnerPtr<IBody> CreateAttachment(const IBody* pBodyToAttach, int faceIndexToAttach, const std::vector<const IBody*>& targetShellBodys,
            const Vector3d& direction, IGraphicsNodeIdAsker* pGraphicsNodeIdAsker, const std::vector<int>* pTargetShellBodyAuxKeys) const = 0;

        /// \brief  多目标面构造附着体
        /// \param  pBodyToAttach              附着前的体
        /// \param  faceIndexToAttach          面在待附着体里的索引，该面将会沿着给定方向，附着到给定目标壳体
        /// \param  targetShellBodys           附着的目标壳体集
        /// \param  direction                  附着方向
        /// \param  pGraphicsNodeIdAsker       拓扑命名查询器(输入空指针，则不生成拓扑命名数据(包括Face,Edge的Id))
        /// \return 新生成的附着后的形体
        GCMP_OBSOLETE_API(2021/12/01, IBodyFactory::CreateAttachment(const IBody*, int, const std::vector<const IBody*>&, const Vector3d&, IGraphicsNodeIdAsker*, const std::vector<int>*))
        virtual OwnerPtr<IBody> CreateAttachment(const IBody* pBodyToAttach, int faceIndexToAttach, const std::vector<const IBody*>& targetShellBodys, const Vector3d& direction, IGraphicsNodeIdAsker* pGraphicsNodeIdAsker) const = 0;

        /// \brief   曲面缝合成体，要求不同曲面完全封闭成体
        ///
        /// \param  surfaces       曲面
        /// \param dDistanceEpsilon  距离容差
        /// \return 缝合的体
        virtual OwnerPtr<IBody> StitchSurfaces(const std::vector<OwnerPtr<ISurface>>& surfaces, double dDistanceEpsilon)const = 0;

        /// \brief   拓扑面缝合成体，要求不同拓扑面存在重合边的情况
        ///
        /// \param  inputFaces       输入的待缝合的面
        /// \param dDistanceEpsilon  缝合容差
        /// \param[out] resultBody  缝合的体
        /// \param  bNeedReverseDir 是否翻转输入面的方向,若需要翻转面的朝向，则传入参数true
        /// \return 错误码
        virtual StitchErrorCode StandardStitchFaces(const std::vector<const IFace*>& inputFaces, double dDistanceEpsilon, OwnerPtr<IBody>& resultBody, bool bNeedReverseDir)const = 0;

        /*!
        *@brief 由给定的屋顶边界线轮廓和坡度角度等参数创建一个屋顶（带拓扑命名）
        *@param[in] const Coordinate3d& plane                                        //屋顶边界线坐标系
        *@param[in] const IPolygon* pSection                                       //屋顶边界线轮廓，支持多个环
        *@param[in] const std::vector<double>& inAngles                                    //屋顶每条边界线的坡度角度
        *@param[in] const std::vector<double>& inHeight                                    //屋顶每条边界线与屋顶基准的高度偏移
        *@param[in] int inEaveMode                                                         //屋顶屋檐的椽截面类型
        *@param[in] double inFascia                                                        //屋顶屋檐的封檐带深度
        *@param[in] const std::vector<Int32>& sketchCrvIndices                             //屋顶每条边界线对应草图索引，用于拓扑命名
        *@return 屋顶
        */
        GCMP_OBSOLETE_API(2020 / 05 / 22, IBodyFactory::CreateRoofBody(const Coordinate3d&, const IPolygon*, const std::vector<double>&, const std::vector<double>&, double,std::wstring*,int,double, const std::vector<Int32>&, const std::vector<SlopeArrowData>&) const) virtual OwnerPtr<IBody> CreateRoofBody(
            const Coordinate3d& plane,                                                                  //屋顶边界线坐标系
            const IPolygon* pSection,                                                                 //屋顶边界线轮廓，支持多个环
            const std::vector<double>& inAngles,                                                              //屋顶每条边界线的坡度角度
            const std::vector<double>& inHeights,                                                             //屋顶每条边界线与屋顶基准的高度偏移
            double inThickness,                                                                               //屋顶厚度
            int inEaveMode = 0,                                                                               //屋顶屋檐的椽截面类型 
            double inFascia = 0.0,                                                                            //屋顶屋檐的封檐带深度
            const std::vector<Int32>& sketchCrvIndices = std::vector<Int32>(),                                //屋顶每条边界线对应草图索引，用于拓扑命名
            const std::vector<SlopeArrowData>& inSlopeArrows = std::vector<SlopeArrowData>()      //屋顶边界线对应坡度箭头数据

        ) const = 0;


    };
    inline IBodyFactory::~IBodyFactory() {}
}
